
from collections import deque
import threading
import time
from beaconmessage import *
import numpy as np
import math

# origin_data=pd.read_csv( 'D:\BaiduNetdiskDownload\higho数据\ '+str(str(i).rjust(2, ' '))+'_tracks.csv')

class CommonCar(threading.Thread):

    """
       车辆线程：每个车辆需要统计自己链路传输持续时间、丢包率、传输成功率
    """
    def __init__(self):

        self.oldNebers = 0   # 记录上一次更新的邻居节点
        self.disRecord = []  # 记录断开的连接

        self.beacon =  {}  # 广播的消息以字典的形式存在

        threading.Thread.__init__(self)

        self.similarMatrix = []

        self.similaryOrder  = []

    def setBeacon(self,beacon):

        self.beacon = beacon

   
    def run(self):
        """
        重写线程的run函数
        :return:
        """
        self.__carMainTask()

   
    def __carMainTask(self):

        while True:
            try:

                time.sleep(1)  # 延时1s

            except Exception as e:
                print(e)
                self.__threadClose()
                return 0

    def broadCast(self):
        """
        广播车辆自己的数据，并查找广播覆盖范围内的车辆
        return:
        """
        return self.beacon


    def receiveBeacon(self, revDir):
        print(self.id," 接收数据:", revDir)


    def getPosition(self):
        return self.position


    def __threadClose(self):
        pass


    def updateNeberList(self,newNebers):
        """
        记录邻居节点的属性,并更新相似度

        邻居节点中的值包含了车辆自己，每个车辆都会计算一遍相似矩阵
        """
        if len(newNebers) > 1:

            #根据异或结果记录哪些断开连接了
            # self.disRecord.append(self.oldNebers ^ newNebers)
            # self.disRecord.append(time.time())

            self.similarMatrix = self.computeSimilarity(newNebers)

            # print("self.similarMatrix :",self.similarMatrix )

            fitable = self.affinityPropagation(self.similarMatrix.copy(), 0.34)

            
            # print ("fitable:", fitable)
            clusters = self.computeCluster(fitable)

            print ("clusters:", clusters)

            #更新值
    

    def formulaDefine(self,beaconI,beaconJ):
        
        """根据矩阵中不同的属性值进行计算"""

        # 首先计算两点之间的坐标距离
        position = (math.sqrt( ((beaconI['x']-beaconJ['x']) ** 2) + ((beaconI['y']-beaconJ['y']) ** 2 ) ) ) / beaconI['range']

        positionFactor = position if position < 1 else 1

        # 计算速度相似性
        speedFactor = (math.fabs(beaconI['v'] - beaconJ['v']) ) /beaconI['vMax']

        # TODO:计算车辆的传输速率
        transFactor = 0

        # TODO:计算车辆的剩余电量
        batterFactor = 0

        similary = positionFactor + speedFactor + transFactor + batterFactor

        return -similary



    def computeSimilarity(self,datalist):

        Similarity = []
        dists = []

        for pointX in datalist:

            self.similaryOrder.append(pointX['id'])


        for pointX in datalist:

            dists.clear()

            for pointY in datalist:

                dists.append( self.formulaDefine(pointX, pointY) ) 

            Similarity.append(dists.copy())
            

        tempSimilarity = np.array(Similarity)
        np.fill_diagonal(tempSimilarity, tempSimilarity.min())

        return tempSimilarity


    def affinityPropagation(self,Similarity, lamda):

        #初始化 吸引矩阵 和 归属 矩阵
        Responsibility = np.zeros_like(Similarity, dtype=np.float16)
        Availability = np.zeros_like(Similarity, dtype=np.float16)

        num = len(Responsibility)

        count = 0
        while count <= 10:
            count += 1
            # update 吸引矩阵

            for Index in range(num):
                # print len(Similarity[Index])
                kSum = [s + a  for s, a in zip(Similarity[Index], Availability[Index])]

                for Kendex in range(num):
                    
                    kfit = self.delete(kSum, Kendex)

                    # print('kfit:',kfit,"max(kfit):",max(kfit))

                    ResponsibilityNew = Similarity[Index][Kendex] - max(kfit)

                    # print('ResponsibilityNew:',ResponsibilityNew)

                    Responsibility[Index][Kendex] = lamda * Responsibility[Index][Kendex] + (1 - lamda) * ResponsibilityNew

                    # print('Responsibility[Index][Kendex]:',Responsibility[Index][Kendex])

            # print("Responsibility", Responsibility)


            # update 归属矩阵

            ResponsibilityT = Responsibility.T

            # print ResponsibilityT, Responsibility

            for Index in range(num):
                iSum = [r for r in ResponsibilityT[Index]]

                for Kendex in range(num):
                    #
                    ifit = self.delete(iSum, Kendex)
                    ifit = filter(self.isNonNegative, ifit)   #上面 iSum  已经全部大于0  会导致  delete 下标错误

                    #   k == K 对角线的情况
                    if Kendex == Index:
                        AvailabilityNew  = sum(ifit)
                    else:
                        result = Responsibility[Kendex][Kendex] + sum(ifit)
                        AvailabilityNew = result if result > 0 else 0
                    Availability[Kendex][Index] = lamda * Availability[Kendex][Index] + (1 - lamda) * AvailabilityNew

            # print("Availability", Availability) 


            # print( "###############################################")
            # print (Responsibility)
            # print (Availability)
            # print ("###############################################")
            return Responsibility + Availability

    def computeCluster(self,fitable):
        clusters = {}
        num = len(fitable)
        for node in range(num):
            fit = list(fitable[node])
            key = fit.index(max(fit))
            if key not in clusters:
                clusters[key] = []

            clusters[key].append(self.similaryOrder[node])

        return clusters
    

    """切片删除 返回新数组"""
    def delete(self,lt, index):
        lt = lt[:index] + lt[index+1:]
        return lt

    def isNonNegative(self,x):
        return x >= 0
    








    


    


